package org.com.yz.dubbo.service.impl;

import cn.hutool.core.date.DateTime;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringEscapeUtils;
import org.com.yz.common.constant.PayConstant;
import org.com.yz.common.core.EPay;
import org.com.yz.common.util.*;
import org.com.yz.dal.dao.mapper.*;
import org.com.yz.dal.dao.model.*;
import org.com.yz.dubbo.api.service.IMchConfigService;
import org.com.yz.dubbo.api.service.ITransactionDetailsService;
import org.com.yz.dubbo.api.service.IWithDrawMchAccntService;
import org.com.yz.dubbo.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 提现接口实现类
 */
@Service(version = "1.0.0", interfaceName = "org.com.yz.dubbo.api.service.IWithDrawMchAccntService")
public class WithDrawMchAccntServiceImpl implements IWithDrawMchAccntService {


    private static final MyLog _log = MyLog.getLog(WithDrawMchAccntServiceImpl.class);

    @Autowired
    private BaseService baseService;
    @Autowired
    private AsyncTask asyncTask;
    @Autowired
    private BankCardMapper bankCardMapper;
    @Autowired
    private WithDrawInfoMapper withDrawInfoMapper;
    @Autowired
    private IMchConfigService iMchConfigService;
    @Autowired
    private ITransactionDetailsService iTransactionDetailsService;
    @Autowired
    private MchAccntMapper mchAccntMapper;

    @Autowired
    private MchAccntChargeUpMapper mchAccntChargeUpMapper;
    @Autowired
    private MchMapper mchMapper;

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    @Autowired
    private StringRedisTemplate redisTemplate;

    private int page = 1;


    /**
     * 提现
     *
     * param parmJso
     * return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public WithDraw withDraw(String parmJso) {
        int flag;
        String result = StringEscapeUtils.unescapeJava(parmJso);
        Request007 rq007 = JSONObject.parseObject(result, Request007.class);
        String mchNo = rq007.getMchNo();//商户号
        String mchAccntNo = rq007.getBizContent().getMchAccntNo();//子商户号
        String orderNo = rq007.getBizContent().getOrderNo();//订单号
        String cardNo = rq007.getBizContent().getCardNo();//银行卡号
        String bsbankNo = rq007.getBizContent().getBsbankNo();//大小额行号
        Long amt = rq007.getBizContent().getAmount();
        RedisLock redisLock3 = new RedisLock(redisTemplate, "withDrawLock", 10 * 10000000, 5000000);
        //1.查询相关账户信息及银行卡信息
        //返回报文承载对象
        WithDraw withDraw = new WithDraw();
        withDraw.setMchAccntNo(mchAccntNo);//账户号
        withDraw.setOrderNo(orderNo);//订单号
        withDraw.setCardNo(cardNo);//银行卡号

        try {
            if (redisLock3.tryLock()) {
                System.out.println("下一个线程进来的时间为：" + System.currentTimeMillis());
                //1.查询提现账户及存管户、准备金、商户可用总余额等账户信息
                Map accntMap = baseService.selectAllAccntInfo(mchNo, mchAccntNo, orderNo);
                MchAccnt depositoryAccnt = (MchAccnt) accntMap.get("depository");//存管户账户信息
                MchAccnt prepayAccnt = (MchAccnt) accntMap.get("prepay");//准备金账户信息
                MchAccnt countAmtAccnt = (MchAccnt) accntMap.get("countamt");//商户可用总余额账户

                //2.查询提现账户的银行卡信息
                String mchNo3 = mchNo;
                String cardNo3 = cardNo;
                String accntType3 = "";
                BankCard withDrawCard = baseService.selectBankCard(mchNo3, cardNo3, mchAccntNo, accntType3);
                Long accntCount = countAmtAccnt.getRemainAmt();//商户可用总余额信息
                //2.判断提现情况，是否超额提现
                // 判断商户可用余额是否支撑提现（是否支持实时提现）
                //**准备金不足，补准备金，查询存管户是否充足，存管户不足，查准备金+存管户是否充足，如果够扣，则请求代发，从准备金代发到存管户，存管户再代发到提现账户
                if (ToolUtil.isEmpty(depositoryAccnt.getRemainAmt())) {//存管户余额为空
                    withDraw.setStatus("2");
                    withDraw.setErrmsg("账户余额不足，无法提现");
                    return withDraw;
                }
                MchAccnt withDrawAccnt = (MchAccnt) accntMap.get("withDraw");//提现账户
                //提现金额 < 商户可用余额（单）
                if (amt <= withDrawAccnt.getRemainAmt()) {
                    if (amt <= accntCount) {//提现金额 < 商户可用余额(非超额提现，不需要准备金)
                        flag = 1;
                    } else {
                        flag = 2;
                        //提现金额 < 商户可用余额（单） > 商户可用总额（非超额提现，需要用准备金）
                        if (prepayAccnt.getRemainAmt() < Math.abs(amt - accntCount)) {
                            withDraw.setStatus("2");
                            withDraw.setErrmsg("准备金余额不足");
                            return withDraw;
                        }
                    }
                } else {
                    //提现金额 > 商户余额（单） < 商户可用余额（总）（超额提现，但不需要准备金）
                    if (amt <= accntCount) {
                        flag = 3;
                    } else {
                        flag = 4;
                        //提现金额 > 商户余额（单） > 商户可用余额（总）（超额提现，且需要准备金）
                        if (prepayAccnt.getRemainAmt() < Math.abs(accntCount - amt)) {
                            withDraw.setStatus("2");
                            withDraw.setErrmsg("准备金余额不足");
                            return withDraw;
                        }
                    }
                }
                //3.提现，并记录数据库
                withDraw = withDrawRecord(orderNo, rq007, withDrawCard, withDraw, flag, accntMap, bsbankNo);
            }
        } catch (Exception e) {
            _log.info("提现异常，抛出到实现类最外层");
            if(ToolUtil.getExceptionMsg(e).contains(PayConstant.RETURN_DEPOSIT_TIMEOUT_ERRORS)){
                throw new RuntimeException(PayConstant.RETURN_DEPOSIT_TIMEOUT_ERRORS,e);
            }else{
                throw new RuntimeException(e);
            }

        } finally {
            redisLock3.unlock();
        }
        return withDraw;
    }


    /**
     * 检查提现请求是否已存在，如果存在，则返回已存在的信息
     * param orderNo
     * param mchAccntNo
     * param mchNo
     * return
     */
    @Transactional(rollbackFor = Exception.class)
    public WithDraw checkWithDraw(String orderNo, String mchAccntNo, String mchNo) throws ParseException {
        WithDraw withDraw1 = baseService.checkWithDraw(orderNo, mchAccntNo, mchNo);
        if (ToolUtil.isNotEmpty(withDraw1)) {
            if ("1".equals(withDraw1.getStatus())) {
                withDraw1.setErrmsg("");
            }
            withDraw1.setTransDate(DateUtil.date2Str(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(withDraw1.getTransDate()), "yyyyMMdd"));//提现日期
            return withDraw1;

        }
        return null;
    }

    /**
     * 提现，并更新存管户、提现账户、商户可用总余额，事务表、存管户资金明细表、提现账户资金明细表
     *
     * @param rq007        请求参数
     * @param withDrawCard 提现银行卡信息
     * @param withDraw     返回报文对象
     * @param flag         提现情况标志
     * @param accntMap     提现所需账户等信息
     * return
     */
    @Transactional(rollbackFor = Exception.class,propagation=Propagation.SUPPORTS)
    public WithDraw withDrawRecord(String trunId, Request007 rq007, BankCard withDrawCard, WithDraw withDraw, int flag, Map accntMap, String bsbankNo) {
        MchAccnt withDrawAccnt = (MchAccnt) accntMap.get("withDraw");//提现账户
        MchAccnt depositoryAccnt = (MchAccnt) accntMap.get("depository");//存管户账户信息
        Long beforeWithDrawAmt = withDrawAccnt.getRemainAmt();//提现账户余额（交易前）
        MchAccnt prepayAccnt = (MchAccnt) accntMap.get("prepay");//准备金
        Long beforePrepayAmt = prepayAccnt.getRemainAmt();
        HisAccntOnway2 onway2Accnt = (HisAccntOnway2) accntMap.get("onway2");//在途2
        MchAccnt countAmtAccnt = (MchAccnt) accntMap.get("countamt");//商户可用余额总
        Long accntCount = countAmtAccnt.getRemainAmt();

        String mchNo = rq007.getMchNo();//商户号
        WithDraw withDraw1 = rq007.getBizContent();
        String mchAccntNo = withDraw1.getMchAccntNo();//子商户号
        String orderNo = withDraw1.getOrderNo();//订单号
        String cardNo = withDraw1.getCardNo();//银行卡号
        String type = withDraw1.getType();//代付类型
        Long amt = withDraw1.getAmount();//提现金额
        String notifyUrl = withDraw1.getNotifyUrl();

        String accntType = withDrawAccnt.getAccntType();//账户类型
        Long beforeMchAmt = depositoryAccnt.getRemainAmt();//存管户余额（交易记录前）
        String outoderNo = MySeq.getOutOder();//平台订单号
        String transtionalNo = UUID.randomUUID().toString().replace("-", "").toLowerCase();//事务号
        Date transTime = new Date();
        boolean isDeduction = false;
        int  fixedPoundage = 0;


        //如果提现需要扣除手续费，则提现金额扣除手续费金额，手续费金额增加到平台分润账户中
        Mch mch = new Mch();
        mch.setMchNo(mchNo);
        List<Mch> mchList = mchMapper.selectMch(mch);
        if(!PayConstant.DEPOSIT_PROFIT.equals(accntType) && mchList.size()>0 && ToolUtil.isNotEmpty(mchList.get(0))){
            fixedPoundage = mchList.get(0).getFixedPoundage();
            if(ToolUtil.isNotEmpty(fixedPoundage) && fixedPoundage!=0){
                amt = amt - fixedPoundage;
                isDeduction = true;
            }
        }
        //1.插入提现记录，更新余额
        insertTransctional(transtionalNo, rq007, mchNo);
        if (flag == 1) {//flag=1：非超额提现，不需要准备金; flag=2:非超额提现，需要准备金; flag =3:超额提现，但不需要准备金;flag=4:超额提现，需要准备金
            //更新存管户余额
            updateDepository(depositoryAccnt, -amt);
        } else if (flag == 2) {
            //记还准备金交易记录表
            insetMchAccntChargeUp(transTime, mchNo, -Math.abs(amt - accntCount));
            //减少准备金余额
            updatePrepay(prepayAccnt, accntCount - amt);
            //记准备金交易记录表
            insertHisPrepay(transTime, mchNo, orderNo, -Math.abs(amt - accntCount), beforePrepayAmt, PayConstant.DEPOSIT_TRAN_WITHDRAW);

            //更新存管户余额（增加准备金过来的钱，减去提现的钱）//分支
            updateDepository(depositoryAccnt, -accntCount);// amt-accntCount -amt

        } else if (flag == 3) {
            //在途2记录一笔超额提现记录
//            insertMchAccntOnway(transTime, mchNo, orderNo, -Math.abs(amt - withDrawAccnt.getRemainAmt()), onway2Accnt.getBalance(), flag);
//            //更改在途2账户
//            updateOnway2(mchNo, -Math.abs(amt - withDrawAccnt.getRemainAmt()));
            //更新存管户月（减去提现的钱）
            updateDepository(depositoryAccnt, -amt);

        } else if (flag == 4) {
            //在途2记录超额提现记录
//            insertMchAccntOnway(transTime, mchNo, orderNo, -Math.abs(amt - withDrawAccnt.getRemainAmt()), onway2Accnt.getBalance(), flag);
//            //更改在途2账户
//            updateOnway2(mchNo, -Math.abs(amt - withDrawAccnt.getRemainAmt()));
            //记还准备金交易记录表
            insetMchAccntChargeUp(transTime, mchNo, -Math.abs(amt - accntCount));
            //记录准备金交易记录明细表
            insertHisPrepay(transTime, mchNo, orderNo, -Math.abs(amt - accntCount), beforePrepayAmt, PayConstant.DEPOSIT_TRAN_WITHDRAW);
            //减少准备金余额
            updatePrepay(prepayAccnt, accntCount - amt);
            //更新存管户余额（增加准备金过来的钱，减去提现的钱）
            updateDepository(depositoryAccnt, -accntCount);//amt - accntCount -amt    9 -0 -9    1 - 0 -1

        }

//                int afterDepositortAmt = (int)(Double.valueOf(depositoryAccnt.getRemain_amt())-amt);
        //更新提现账户
        withDrawAccnt.setRemainAmt(-amt);
        withDrawAccnt.setUpdateTime(new DateTime());
        baseService.updateMchAmtNoZero(withDrawAccnt);
        //更新商户可用总余额
        countAmtAccnt.setRemainAmt(-amt);
        countAmtAccnt.setUpdateTime(new DateTime());
        baseService.updateMchAmt(countAmtAccnt);
        //插入存管户历史交易明细数据
        insertHisMch(transTime, transtionalNo, mchNo, orderNo, -Math.abs(depositoryAccnt.getRemainAmt()), beforeMchAmt, beforeMchAmt - Math.abs(depositoryAccnt.getRemainAmt()), PayConstant.DEPOSIT_TRAN_WITHDRAW);
        //插入提现账户历史交易明细数据
        insertWithdrawAccnt(transTime, transtionalNo, accntType, mchNo, mchAccntNo, orderNo, -amt, beforeWithDrawAmt, beforeWithDrawAmt - amt, PayConstant.DEPOSIT_TRAN_WITHDRAW);
        //插入提现记录表
        insertWithdrawInfo(transTime, transtionalNo, outoderNo, cardNo, mchNo, mchAccntNo, orderNo, amt, beforeWithDrawAmt - amt, flag, notifyUrl,fixedPoundage);
        //*提现涉及手续费，在各个表里增加类型为手续费，多记一笔明细数据


        //TODO 如果包含手续费，则将手续费分情况从对应账户中扣除 反向加钱时，存管户有2条记录，准备金有2条记录，提现记录中需要记录手续费金额

        if(isDeduction){
            //如果需要扣除手续费，则将手续费增加到分润账户中
            if(flag == 2 || flag ==4){
                insetMchAccntChargeUp(transTime, mchNo, -(long) fixedPoundage);
                updatePrepay(prepayAccnt, -(long) fixedPoundage);
                insertHisPrepay(transTime, mchNo, orderNo, -(long) fixedPoundage, beforePrepayAmt -Math.abs(amt - accntCount), "poundage");
                updateDepository(depositoryAccnt, -accntCount);
            }else if(flag == 1 || flag ==3){
                    updateDepository(depositoryAccnt, -(long) fixedPoundage);
            }
            //插入存管户历史交易明细数据
            insertHisMch(transTime, transtionalNo, mchNo, orderNo, -Math.abs(depositoryAccnt.getRemainAmt()), beforeMchAmt - Math.abs(depositoryAccnt.getRemainAmt()), beforeMchAmt - Math.abs(depositoryAccnt.getRemainAmt()) -Math.abs(depositoryAccnt.getRemainAmt()) , "poundage");
            MchAccnt profitAccnt = queryMchAccntByMchNo(mchNo,PayConstant.DEPOSIT_PROFIT);
            //更改分润账户余额
            updateMchAccnt(mchNo, (long) fixedPoundage);

            //记录分润账户明细
            insertHisMchProfit(transtionalNo, orderNo,"poundage" ,mchNo, profitAccnt.getRemainAmt(), (long) fixedPoundage, profitAccnt.getRemainAmt()+fixedPoundage,transTime);
            //更新提现账户
            withDrawAccnt.setRemainAmt(-(long) fixedPoundage);
            withDrawAccnt.setUpdateTime(new DateTime());
            baseService.updateMchAmtNoZero(withDrawAccnt);
            //插入提现账户历史交易明细数据
            insertWithdrawAccnt(transTime, transtionalNo, accntType, mchNo, mchAccntNo, orderNo, -(long) fixedPoundage, beforeWithDrawAmt - amt, beforeWithDrawAmt - amt -(long) fixedPoundage, "poundage");
        }

        String url = rq007.getBizContent().getNotifyUrl();
        //2.调用兴业银行代付（收付直通车/银企直联/超级网银）
        Map<String, String> resultMap = null;//代付
        try {
            resultMap = withDraw(mchAccntNo, trunId, mchNo, type, orderNo, cardNo, amt, withDrawCard, url, bsbankNo);
        } catch (Exception e) {
            throw  new RuntimeException(PayConstant.RETURN_DEPOSIT_TIMEOUT_ERRORS);
        }
        //返回提现信息
        if (resultMap.get("status").equals("2")) {//代付失败
            withDraw.setStatus("2");
            withDraw.setErrmsg(resultMap.get("message"));
            return withDraw;
        } else {//代付成功或未决（返回相应数据）
            withDraw.setOutOrderNo(outoderNo);//平台订单号
            withDraw.setTransDate(DateUtil.date2Str(transTime, "yyyyMMdd"));//提现日期
            withDraw.setTransTime(DateUtil.date2Str(transTime, "HHmmss"));//提现时间
            withDraw.setTransFee(Integer.parseInt(resultMap.get("transFee")));//提现手续费
            withDraw.setAmount(amt);//提现金额
            if (resultMap.get("status").equals("3")) {//代发未决
                withDraw.setAccntAmtAfter(0L);//提现后账户余额（）
                withDraw.setStatus("3");
            } else { //代付成功
                Long afterWithDrawAmt =beforeWithDrawAmt - amt;//提现账户余额减掉
                withDraw.setAccntAmtAfter(afterWithDrawAmt);//提现后账户余额（）//此时提现成功，返回数据
                withDraw.setStatus("1");
                //插入事务数据
            }
        }
        return withDraw;
    }

    /**
     * 代付（收付直通车/银企直联）
     *
     * param type         代付类型
     * param orderNo      订单号
     * param cardNo       提现卡号
     * param amt          提现金额
     * param withDrawCard 提现银行卡信息
     * return
     */
    public Map<String,String> withDraw(String mchAccntNo, String trunId, String mchNo, String type, String orderNo, String cardNo, Long amt, BankCard withDrawCard, String url, String bsbankNo) throws Exception {
        Map<String, String> resultMap = new ConcurrentHashMap<>();
        if ("RPAYM".equals(type)) {
            //收付直通车
            try {
                resultMap = ztc(mchNo, orderNo, withDrawCard, cardNo, amt);
            } catch (Exception e) {
                _log.info("收付直通车联代付异常");
                _log.info(ToolUtil.getExceptionMsg(e));
                resultMap.put("status", "2");
                resultMap.put("message", "收付直通车代付异常");
            }
        } else if ("HOH".equals(type) || "SUPER".equals(type)) {
            //银企直联
                resultMap = yqzl(mchAccntNo, trunId, amt, mchNo, withDrawCard, url, bsbankNo, type);

        }
        return resultMap;
    }


    /**
     * 更新分润账户信息
     * <p>
     * param
     * param
     * return
     */
    private int updateMchAccnt(String mchNo,  Long amount) {
        MchAccnt mchAccntBefore = new MchAccnt();
        mchAccntBefore.setMchNo(mchNo);
        mchAccntBefore.setAccntType(PayConstant.DEPOSIT_PROFIT);
        mchAccntBefore.setRemainAmt(amount);
        mchAccntBefore.setUpdateTime(new DateTime( ));
        return baseService.updateMchAmtNoZero(mchAccntBefore);
    }

    /**
     * 收付直通车
     *
     * param mchNo
     * param orderNo
     * param withDrawCard
     * param cardNo
     * param amt
     * return
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String,String> ztc(String mchNo, String orderNo, BankCard withDrawCard, String cardNo, Long amt) {
        Map<String, String> resultMap = new ConcurrentHashMap<>();
        String result = EPay.pyPay(mchNo, orderNo, withDrawCard.getBankNo(), cardNo, withDrawCard.getUserName(), withDrawCard.getCardType(), AmountUtil.convertCent2Dollar(String.valueOf(amt)), "提现");
        JSONObject po;
        try {
            po = JSONObject.parseObject(result);
            if (ToolUtil.isNotEmpty(po.getString("errcode"))) {//代付异常
                resultMap.put("status", "2");
                resultMap.put("message", po.getString("errmsg"));
            } else {
                if ("1".equals(po.getString("transStatus"))) {//代发成功
                    resultMap.put("status", "1");
                    resultMap.put("message", "代付成功");
                    updateWithDrawInfo(orderNo, mchNo, "1", "提现成功");
                } else if (po.getString("transStatus").equals("2")) {//代发失败
                    resultMap.put("status", "2");
                    resultMap.put("message", po.getString("remark"));
                    WithDrawInfo withdrawInfo = new WithDrawInfo();
                    withdrawInfo.setOrderNo(orderNo);
                    withdrawInfo.setMchNo(mchNo);
                    List<WithDrawInfo> withDrawInfoList = withDrawInfoMapper.select(withdrawInfo);
                    if (withDrawInfoList.size() > 0 && withDrawInfoList.get(0) != null) {
                        withDrawBack(withDrawInfoList.get(0),"2", po.getString("remark"));
                    }
                } else {
                    resultMap.put("status", "3");
                    resultMap.put("message", "代付未决");
                }
                resultMap.put("transFee", AmountUtil.convertDollar2Cent(po.getString("transFee")));//交易手续费，元转分
            }
        } catch (Exception e) {
            throw new RuntimeException("提现失败！银行未知错误");
        }
        return resultMap;
    }


    /**
     * 银企直联
     *
     * param trunId
     * param amt
     * param mchNo
     * param withDrawCard
     * return
     * throws Exception
     */
    public Map<String,String> yqzl(String mchAccntNo, String trunId, Long amt, String mchNo, BankCard card, String url, String bsbankNo, String type) throws Exception {
        String isSuper = "1";//是否超级网银
        /*if(amt > 5000000){
            isSuper="0";
        } */
        if (PayConstant.DEPOSIT_WITHDRAWTYPE_HOH.equals(type)) {
            isSuper = "0";
        }
        String isSameBank = "N"; //默认N 是否同行
        String isSameCity = "N"; //默认N 是否同城
        if ("兴业银行".equals(card.getBankName())) {
            isSameCity = "Y"; //同行
        }
        /*if (card.getBankBranchName().contains("杭州")) {
            isSameCity = "Y"; //同城
        }*/
        String cardNo = card.getCardNo();//银行卡号
        String accountName = card.getUserName();//户名
        String bankName = card.getBankName();//收款人开户行名称。非兴业银行账号时，收款人开户行名称必输,且不应包含“兴业银行”字样，否则返回“您的收款账号不是兴业银行账00号”并不允许提交，最大50位
        String city = "";
        if (ToolUtil.isNotEmpty(card.getBankBranchName())) {
            city = card.getBankBranchName().substring(0, 2);////收款人城市，同城无需填写，异地汇款填入收款行城市名称（建议客户端控制，否则可能不能正常转账），最大30位
        }
        String bankNum = "";
        String bankCardBin = cardNo.substring(0, 6);
        Map<String, String> resultMap = new ConcurrentHashMap<>();//返回银企直联接口集合
        if (ToolUtil.isNotEmpty(bsbankNo)) {
            bankNum = bsbankNo;
        } else {
            List<BankCardBin> bankCardBinList = bankCardMapper.getBankCardBinByBankName(bankName);//通过银行名称查询卡宾信息，获取行号
            if (ToolUtil.isNotEmpty(bankCardBinList) && ToolUtil.isNotEmpty(bankCardBinList.get(0))) {
                bankNum = bankCardBinList.get(0).getBankNum();
            } else {
                BankCardBin bankCardBin1 = bankCardMapper.getBankCardBinByCardBin(bankCardBin);//通过卡号匹配卡宾信息，获取行号
                if (ToolUtil.isNotEmpty(bankCardBin1)) {
                    bankNum = bankCardBin1.getBankNum();
                }
            }
        }
        //调用转账接口
        WithdrawPay withdrawPay ;
            //如果是超级网银
            if ("1".equals(isSuper)) {
                withdrawPay = WithdrawPayUtil.withdrawPay(mchNo, trunId, isSameBank, isSameCity, cardNo, accountName, bankName, bankNum, city, AmountUtil.convertCent2Dollar(String.valueOf(amt)), isSuper, "0", "超级网银--提现");
            } else {//如果是普通网银
                withdrawPay = WithdrawPayUtil.withdrawPay(mchNo, trunId, isSameBank, isSameCity, cardNo, accountName, bankName, bankNum, city, AmountUtil.convertCent2Dollar(String.valueOf(amt)), isSuper, "0", "普通网银--提现");
            }
            resultMap.put("transFee", "0");
            if ("FAIL".equals(withdrawPay.getXferprccode())) {//失败
                resultMap.put("status", "2");
                resultMap.put("message", withdrawPay.getMessage());
                WithDrawInfo withdrawInfo = new WithDrawInfo();
                withdrawInfo.setOrderNo(trunId);
                withdrawInfo.setMchNo(mchNo);
                List<WithDrawInfo> withDrawInfoList = withDrawInfoMapper.select(withdrawInfo);
                if (withDrawInfoList.size() > 0 && withDrawInfoList.get(0) != null) {
                    withdrawInfo = withDrawInfoList.get(0);
                    withDrawBack(withdrawInfo,"2",withdrawPay.getMessage());//加回数据
                }
            } else if ("PAYOUT".equals(withdrawPay.getXferprccode())) { //成功
                if ("0".equals(isSuper)) {
                    resultMap.put("status", "3");
                } else {
                    resultMap.put("status", "1");
                }
                resultMap.put("message", withdrawPay.getMessage());
                // 存在第一次请求直接成功的非常规操作，以前的订单号用过，直接调银行接口提示成功
            } else if ("PENDING".equals(withdrawPay.getXferprccode())) {//未决
                resultMap.put("status", "3");
                resultMap.put("message", withdrawPay.getMessage());
                //异步查询转账交易
                asyncTask.withDrawPayQueryByYqzl(trunId, mchAccntNo, withdrawPay, mchNo, cardNo, url);
            }
        return resultMap;
    }


    /**
     * 记录在途2交易明细，更新在途2交易明细总额
     *
     * param mchNo     商户号
     * param orderNo   订单号  标识提现
     * param eventAmt  事件金额
     * param beforeAmt 事件前金额
     * param flag
     */
    private void insertMchAccntOnway(Date transTime, String mchNo, String orderNo, Long eventAmt, Long beforeAmt, int flag) {

        HisAccntOnway2 hisAccntOnway2 = new HisAccntOnway2();
        hisAccntOnway2.setMchNo(mchNo);//商户号
        hisAccntOnway2.setOrderNo(orderNo);//订单号
        hisAccntOnway2.setTransactionNo("");//事务号
        hisAccntOnway2.setEvent("withdraw");//
        hisAccntOnway2.setEventAmt(eventAmt);//事件金额(超出提现账户可用余额部分)
        hisAccntOnway2.setEventTime(transTime);
        hisAccntOnway2.setAccntAmtBefore(beforeAmt);//事件发生前余额
        if (flag == 4) {
            hisAccntOnway2.setFlag("1");
        } else {
            hisAccntOnway2.setFlag("0");
        }
        hisAccntOnway2.setAccntAmtAfter(beforeAmt + hisAccntOnway2.getEventAmt());//事件发生后金额
        hisAccntOnway2.setCreateTime(new DateTime());
        hisAccntOnway2.setType("detailed");
        baseService.insertHisAccntOnway2(hisAccntOnway2);

        HisAccntOnway2 hisAccntOnway21 = new HisAccntOnway2();
        hisAccntOnway21.setBalance(hisAccntOnway2.getAccntAmtAfter());
        hisAccntOnway21.setType("count");
        hisAccntOnway21.setMchNo(mchNo);
        baseService.updateHisAccntOnway2(hisAccntOnway21);
    }

    /**
     * 记录还准备金记录表，更新还准备金明细总额
     *
     * param mchNo       商户号
     * param chargeUpAmt 事件金额
     */
    @Transactional(rollbackFor = Exception.class)
    public void insetMchAccntChargeUp(Date transTime, String mchNo, Long chargeUpAmt) {
        MchAccntChargeUp mchAccntChargeUp = new MchAccntChargeUp();
        mchAccntChargeUp.setMchNo(mchNo);//商户号
        mchAccntChargeUp.setAccntTypeLender("prepay");//出借方
        mchAccntChargeUp.setAccntTypeBorrower("depository");//借方
        mchAccntChargeUp.setChargeUpTime(transTime);//挂账时间
        mchAccntChargeUp.setIdDepositTransaction("");//事务号
        mchAccntChargeUp.setStatu("0");//挂账状态
        mchAccntChargeUp.setChargeUpAmt(chargeUpAmt);
        mchAccntChargeUp.setType("detailed");//挂账类型（明细）
        mchAccntChargeUpMapper.insert(mchAccntChargeUp);

        MchAccntChargeUp mchAccntChargeUp1 = new MchAccntChargeUp();
        mchAccntChargeUp1.setMchNo(mchNo);
        mchAccntChargeUp1.setType("count");
        mchAccntChargeUp1.setBalance(mchAccntChargeUp.getChargeUpAmt());
        mchAccntChargeUp1.setUpdateTime(new DateTime());
        mchAccntChargeUpMapper.updateChargeUpAmt(mchAccntChargeUp1);
    }

    /**
     * 记录准备金历史交易明细
     *
     * param mchNo           商户号
     * param orderNo         订单号
     * param eventAmt        事件金额
     * param beforePrepayAmt
     */
    private void insertHisPrepay(Date transTime, String mchNo, String orderNo, Long eventAmt, Long beforePrepayAmt, String event) {

        HisAccntPrepay hisAccntPrepay = new HisAccntPrepay();
        hisAccntPrepay.setMchNo(mchNo);//商户号
        hisAccntPrepay.setOrderNo(orderNo);//订单号
        hisAccntPrepay.setTransactionNo("");//事务号
        hisAccntPrepay.setEvent(event);//
        hisAccntPrepay.setEventAmt(eventAmt);//事件金额(超出提现账户可用余额部分)
        hisAccntPrepay.setEventTime(transTime);
        hisAccntPrepay.setAccntAmtBefore(beforePrepayAmt);//事件发生前余额
        hisAccntPrepay.setAccntAmtAfter(beforePrepayAmt + hisAccntPrepay.getEventAmt());//事件发生后金额
        hisAccntPrepay.setCreateTime(new DateTime());
        baseService.insertHisPrepay(hisAccntPrepay);
    }


    /**
     * 插入存管户历史资金交易明细表
     *
     * param mchNo        电商平台号
     * param orderNo      订单号
     * param amt          提现金额
     * param beforeMchAmt 提现前余额
     * return
     */
    private void insertHisMch(Date transTime, String transtionalNo, String mchNo, String orderNo, Long amt, Long beforeMchAmt, Long afterMchAmt, String event) {
        //更新存管户历史记录表
        HisAccntMch hisMchAccnt = new HisAccntMch();
        hisMchAccnt.setMchNo(mchNo);//商户号
        hisMchAccnt.setOrderNo(orderNo);//订单号
        hisMchAccnt.setTransactionNo(transtionalNo);//事务号
        hisMchAccnt.setEvent(event);//事件名称
        hisMchAccnt.setEventAmt(amt);//事件金额
        hisMchAccnt.setEventTime(transTime);
        hisMchAccnt.setAccntAmtBefore(beforeMchAmt);//事件发生前余额
        hisMchAccnt.setAccntAmtAfter(afterMchAmt);//事件发生后金额
        hisMchAccnt.setCreateTime(new DateTime());
        baseService.insertHisMchAccnt(hisMchAccnt);
    }

    /**
     * 插入提现账户历史资金交易明细表
     *
     * param transtionalNo
     * param accntType
     * param mchNo
     * param mchAccntNo
     * param orderNo
     * param amt
     * param beforeWithDrawAmt
     * param afterAmt
     * return
     */
    private void insertWithdrawAccnt(Date transTime, String transtionalNo, String accntType, String mchNo, String mchAccntNo, String orderNo, Long amt, Long beforeWithDrawAmt, Long afterAmt, String event) {
        if ("mchsub".equals(accntType)) {
            HisAccntMchSub hisAccntMchSub = new HisAccntMchSub();
            hisAccntMchSub.setMchNo(mchNo);//商户号
            hisAccntMchSub.setMchAccntNo(mchAccntNo);//子商户账户号
            hisAccntMchSub.setOrderNo(orderNo);//订单号
            hisAccntMchSub.setTransactionNo(transtionalNo);//事务号
            hisAccntMchSub.setEvent(event);//事件名称
            hisAccntMchSub.setEventAmt(amt);//事件金额
            hisAccntMchSub.setEventTime(transTime);//事件时间
            hisAccntMchSub.setAccntAmtBefore(beforeWithDrawAmt);//事件发生前余额
            hisAccntMchSub.setAccntAmtAfter(afterAmt);//事件发生后金额
            hisAccntMchSub.setCreateTime(new DateTime());//创建时间
            baseService.insertHisMchASub(hisAccntMchSub);
        }
        if ("profit".equals(accntType)) {
            HisAccntProfile hisAccntProfile = new HisAccntProfile();
            hisAccntProfile.setMchNo(mchNo);
            hisAccntProfile.setOrderNo(orderNo);//订单号
            hisAccntProfile.setTransactionNo(transtionalNo);//事务号
            hisAccntProfile.setEvent(event);//事件名称
            hisAccntProfile.setEventAmt(amt);//事件金额
            hisAccntProfile.setEventTime(transTime);//事件时间
            hisAccntProfile.setAccntAmtBefore(beforeWithDrawAmt);//事件发生前余额
            hisAccntProfile.setAccntAmtAfter(afterAmt);//事件发生后金额
            hisAccntProfile.setCreateTime(new DateTime());//创建时间
            baseService.insertHisProfile(hisAccntProfile);
        }
    }


    /**
     * 插入事务数据
     *
     * param transtionalNo
     * param rq007
     * param mchNo
     * return
     */
    private void insertTransctional(String transtionalNo, Request007 rq007, String mchNo) {
        DepositTransaction des = new DepositTransaction();
        des.setTransactionNo(transtionalNo);//事务号
        des.setOutTransNo(rq007.getOutTransNo());//外部追踪号
        des.setIdMchAccntChargeUp(0);
        des.setCreateTime(new DateTime());//创建时间
        des.setTransactionType("withdraw");//事务类型
        des.setUpdateTime(new DateTime());//更新时间
        des.setMchNo(mchNo);//商户号
        //更新事务表
        baseService.insetDeposiTranction(des);
    }

    /**
     * 插入提现记录表
     *
     * param transtionalNo
     * param trunId
     * param cardNo
     * param mchNo
     * param mchAccntNo
     * param orderNo
     * param amt
     * param afterAmt
     * param flag
     * return
     */
    private void  insertWithdrawInfo(Date transTime, String transtionalNo, String trunId, String cardNo, String mchNo, String mchAccntNo, String orderNo, Long amt, Long afterAmt, int flag, String notifyUrl,long transFee) {
        WithDrawInfo withDrawInfo = new WithDrawInfo();
        withDrawInfo.setCardNo(cardNo);//提现卡号
        withDrawInfo.setFeeBear("withdraw");//承担方（platform:平台承担，withdraw：提现账户承担）
        withDrawInfo.setMchAccntNo(mchAccntNo);//账户号
        withDrawInfo.setMchNo(mchNo);//商户号
        withDrawInfo.setOrderNo(orderNo);//订单号
//       withDrawInfo.setRemark("提现成功-余额扣减");//备注信息
        withDrawInfo.setAfterAmt(afterAmt);
        withDrawInfo.setSno(trunId);//平台订单号
        withDrawInfo.setStatus("3");//提现状态
        withDrawInfo.setTransAmt(amt);//提现金额
        withDrawInfo.setTranscationalNo(transtionalNo);//事务号
//       withDrawInfo.setRemark(resultMap.get("message"));
        withDrawInfo.setTransFee(transFee);//提现手续费
        withDrawInfo.setTransDate(DateUtil.date2Str(transTime, DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS));//提现日期
        withDrawInfo.setTransTime(DateUtil.date2Str(transTime, "HHmmss"));//提现时间
        withDrawInfo.setRemark1(String.valueOf(flag));
        withDrawInfo.setNotifyUrl(notifyUrl);
        baseService.insetWithDraw(withDrawInfo);
    }

    /**
     * 更新存管户账户信息
     *
     * param depositoryAccnt
     * param amt
     * return
     */
    private void updateDepository(MchAccnt depositoryAccnt, Long amt) {
        depositoryAccnt.setRemainAmt(amt);//存管户账户余额减掉
        depositoryAccnt.setUpdateTime(new DateTime());
        baseService.updateMchAmt(depositoryAccnt);
    }

    /**
     * 更新准备金
     *
     * param prepayAccnt
     * param amt
     */
    private void updatePrepay(MchAccnt prepayAccnt, Long amt) {
        prepayAccnt.setRemainAmt(amt);
        prepayAccnt.setUpdateTime(new DateTime());
        baseService.updateMchAmt(prepayAccnt);
    }

    /**
     * 更新在途2账户余额
     *
     * param mchNo
     * param amt
     */
    private void updateOnway2(String mchNo, Long amt) {
        MchAccnt mchAccnt = new MchAccnt();
        mchAccnt.setMchNo(mchNo);
        mchAccnt.setAccntType("onway2");
        mchAccnt.setRemainAmt(amt);
        baseService.updateMchAmtNoZero(mchAccnt);
    }


    public List<WithDrawInfo> selectWithDrawInfo(WithDrawInfo withDrawInfo) {
        return baseService.selectWithdrawInfo(withDrawInfo);
    }

    public int updateWithDrawInfo(WithDrawInfo withDrawInfo) {
        return baseService.updateWithDrawInfo(withDrawInfo);
    }


    @Override
    public void httpStatus(WithDrawInfo withDrawInfo) {
        withDrawBack(withDrawInfo,"","");
    }


    /**
     * 普通网银--根据提现未决记录，查询对应账户的交易流水，失败后异步通知，并加回对应金额
     * **因为普通网银转账，如果失败会有两条流水，所以无法确定成功，只有定时将前两个工作日的提现置为成功（提现了超过两天还没失败就成功）
     * **定时查失败的逻辑，记录每次定时的页数，下次从这个记录页查
     *
     * param
     */
    public void httpStatus(Map<String, List<WithDrawInfo>> withDrawInfoMap, int page2) throws InterruptedException {
        String lastDate = DateUtil.getAfterDayDate("-1").substring(0, 10);//当前日期的前一天
        String oldDate;//起始日期
        String newDate;//截止日期
        TrunListPage trunListPage;//流水记录页信息
        Map<String, Object> objectMap;
        List<MchConfig> mchConfigList;//商户配置信息
        for (Map.Entry<String, List<WithDrawInfo>> entry : withDrawInfoMap.entrySet()) {
            String mchNo = entry.getKey();//商户号
            List<WithDrawInfo> withDrawInfoList = entry.getValue();
            MchConfig mchConfig = new MchConfig();
            mchConfig.setMchNo(mchNo);
            mchConfig.setAccntType("0");
            //根据电商平台号，查询商户配置信息
            mchConfigList = iMchConfigService.listCongi(mchConfig);
            MchConfig config = mchConfigList.get(0);
            // 查询流水记录页数表，每次都去查询一次前一天的截止页数，补足定时任务空隙漏掉的交易流水，如果查过一次，则置分页记录状态为1，下一次定时就不再查询
            oldDate = cn.hutool.core.date.DateUtil.now();
            newDate = cn.hutool.core.date.DateUtil.now();
            trunListPage = baseService.selectTrunListPageInfo(mchNo, lastDate, "0");//查询前一天的记录页数
            if (ToolUtil.isNotEmpty(trunListPage)) {
                page2 = Integer.parseInt(trunListPage.getPage());
                //调用dopost方法//查前一天未查完的交易流水
                objectMap = iTransactionDetailsService.doPost(lastDate, lastDate, page2, 1, config, "提现未决记录");
                if (ToolUtil.isNotEmpty(objectMap.get("errMsg"))) {
                    _log.info(mchNo + "---在途2平账查询流水:" + objectMap.get("errMsg"));
                    return;
                }
                queryTrunDetail(objectMap, withDrawInfoList);
                baseService.updateTrunListPageInfo(mchNo, lastDate);
            }
            // 始终查询当天流水，并记录此次定时任务查询截止的页数，下次继续从这个页数查
            trunListPage = baseService.selectTrunListPageInfo(mchNo, DateUtil.getDay(), "0");//查询当天的记录页数
            if (ToolUtil.isEmpty(trunListPage)) {
                //如果未找到今天的记录，则插入一条记录
                baseService.insertTrunListPage(mchNo, DateUtil.getDay(), "0");
                page2 = 1;
            } else {
                page2 = Integer.parseInt(trunListPage.getPage());//获取应该继续查下去的页数

            }
            //查询当天的流水
            objectMap = iTransactionDetailsService.doPost(oldDate, newDate, page2, 1, config, "提现未决记录");
            if (ToolUtil.isNotEmpty(objectMap.get("errMsg"))) {
                _log.info(mchNo + "---在途2平账查询流水:" + objectMap.get("errMsg"));
                return;
            }
            page2 = (int) objectMap.get("page");
            queryTrunDetail(objectMap, withDrawInfoList);
            //23:59分前，都更新page到当天的记录里
            baseService.updateTrunListPageInfo(mchNo, newDate.substring(0, 10), String.valueOf(page2));
        }
    }


    /**
     * 解析流水
     *
     * param objectMap
     * param withDrawInfoList
     * throws InterruptedException
     */
    @SuppressWarnings("unchecked")
    private void queryTrunDetail(Map objectMap, List<WithDrawInfo> withDrawInfoList) throws InterruptedException {
        if (ToolUtil.isNotEmpty(objectMap) && objectMap.size() > 0) {
            //是否有下一页
            //每一页的交易明细
            List<TransactionDetails> transactionDetailslist = (List<TransactionDetails>) objectMap.get("transactionDetailList");
            for (WithDrawInfo withDrawInfo : withDrawInfoList) {
                for (TransactionDetails transactionDetails : transactionDetailslist) {
                    //截取|后面的字符 用来匹配标识
                    //String memo = transactionDetails.getMemo().substring(transactionDetails.getMemo().lastIndexOf("|") + 1);
                    //获取失败交易流水的金额
                    String transAmt = AmountUtil.convertDollar2Cent(transactionDetails.getTrnamt().toString());
                    //获取交易失败流水的卡号
                    String transCardNo = transactionDetails.getCorrelateAcctid();
                    String attachinfo = transactionDetails.getAttachinfo();
                    String businessType = transactionDetails.getBusinesstype();

                    if (transAmt.equals(String.valueOf(withDrawInfo.getTransAmt())) && transCardNo.equals(withDrawInfo.getCardNo()) && "银行退票".equals(businessType)) {//失败
                        // 如果金额跟卡号能核对上，则根据流水号attachinfo 去匹配失败交易流水记录表，看看有没有对应的流水已被匹配过
                        //根据交易流水号去失败记录表里查询，如果没有查询到，代表新的记录，则可以用作匹配
                        ErrorTransactionDetails errorTransactionDetails = baseService.selectErrorTransactionDetail(withDrawInfo.getMchNo(), attachinfo);
                        if (ToolUtil.isEmpty(errorTransactionDetails)) {
                            //更改提现记录状态、加回扣减金额、
                            int back = withDrawInfoBack(withDrawInfo, transactionDetails);
                            //发送异步通知接口，五分钟一次，共发送5次
                            if (back > 0) {
                                asyncTask.withDrawNotify(withDrawInfo, withDrawInfo.getNotifyUrl(), "3", "提现失败！");
                            }
                        }
                    }
                }
            }

        }
    }


    /**
     * 更改提现记录，加回-扣减金额
     *
     * param withDrawInfo
     * param transactionDetails
     * return
     */
    @Transactional(rollbackFor = Exception.class)
    public int withDrawInfoBack(WithDrawInfo withDrawInfo, TransactionDetails transactionDetails) {
        withDrawBack(withDrawInfo,"2",transactionDetails.getMemo().substring(transactionDetails.getMemo().lastIndexOf("|") + 1));
        // 已经匹配过的流水记录，插入失败交易流水记录表
        ErrorTransactionDetails errorTransactionDetails1 = new ErrorTransactionDetails();
        ClassRefUtil.setFieldValue(errorTransactionDetails1, ClassRefUtil.getFieldValueMap(transactionDetails, "1"), "1");
        errorTransactionDetails1.setMchno(withDrawInfo.getMchNo());
        return baseService.insertErrorTransactionDetail(errorTransactionDetails1);
    }

    /**
     * 更改提现记录为成功
     *
     * param orderNo
     * param mchNo
     * param status
     * param remark
     */
    @Override
    public void updateWithDrawInfoSuccess(String orderNo, String mchNo, String status, String remark) {
        updateWithDrawInfo(orderNo, mchNo, status, remark);
    }

    /**
     * 更新提现记录状态
     *
     * param orderNo
     * param mchNo
     * return
     */
    private void updateWithDrawInfo(String orderNo, String mchNo, String status, String remark) {
        WithDrawInfo withDrawInfo = new WithDrawInfo();
        withDrawInfo.setMchNo(mchNo);//商户号
        withDrawInfo.setStatus(status);
        withDrawInfo.setOrderNo(orderNo);//订单号
        withDrawInfo.setRemark(remark);
        withDrawInfo.setUpdateTime(cn.hutool.core.date.DateUtil.now());//提现时间
        updateWithDrawInfo(withDrawInfo);
    }
    /**
     * //记录退还记录
     *
     * param withDrawInfo
     */
    @Transactional(rollbackFor = Exception.class)
    public void withDrawBack(WithDrawInfo withDrawInfo,String status,String errMsg) {
        Map accntMap = baseService.selectAllAccntInfo(withDrawInfo.getMchNo(), withDrawInfo.getMchAccntNo(), withDrawInfo.getOrderNo());
        String mchNo = withDrawInfo.getMchNo();

        MchAccnt withDrawAccnt = (MchAccnt) accntMap.get("withDraw");//提现账户
        MchAccnt depositoryAccnt = (MchAccnt) accntMap.get("depository");//存管户账户信息
        Long beforeWithDrawAmt = withDrawAccnt.getRemainAmt();//提现账户余额（交易前）
        MchAccnt prepayAccnt = (MchAccnt) accntMap.get("prepay");//准备金
        Long beforePrepayAmt = prepayAccnt.getRemainAmt();
        HisAccntOnway2 onway2Accnt = (HisAccntOnway2) accntMap.get("onway2");//在途2
        MchAccnt countAmtAccnt = (MchAccnt) accntMap.get("countamt");//商户可用余额总
        String mchAccntNo = withDrawInfo.getMchAccntNo();//子商户号
        String orderNo = withDrawInfo.getOrderNo();//订单号
        Long amt = withDrawInfo.getTransAmt();//提现金额

        //根据订单号查询  准备金余额明细、在途2余额明细(如果有手续费，会有两条记录)

        HisAccntPrepay hisAccntPrepay = new HisAccntPrepay();
        hisAccntPrepay.setMchNo(mchNo);
        hisAccntPrepay.setOrderNo(orderNo);
        List<HisAccntPrepay> hisAccntPrepayInfoList = baseService.selectHisAccntPrepayList(hisAccntPrepay);//准备金明细
        Long prepayAmt = 0L,prepayAmt2 =0L;
        if (ToolUtil.isNotEmpty(hisAccntPrepayInfoList)) {
            if(hisAccntPrepayInfoList.size()>1){
                if("withdraw".equals(hisAccntPrepayInfoList.get(0).getEvent())){
                    prepayAmt = hisAccntPrepayInfoList.get(0).getEventAmt(); //记录的扣除准备金额
                    prepayAmt2 = hisAccntPrepayInfoList.get(1).getEventAmt(); //记录的扣除准备金额2
                }else{
                    prepayAmt2 = hisAccntPrepayInfoList.get(0).getEventAmt(); //记录的扣除准备金额
                    prepayAmt = hisAccntPrepayInfoList.get(1).getEventAmt(); //记录的扣除准备金额2
                }
            }else{
                prepayAmt = hisAccntPrepayInfoList.get(0).getEventAmt();
            }
        }

        HisAccntOnway2 hisAccntOnway2 = new HisAccntOnway2();
        hisAccntOnway2.setMchNo(mchNo);
        hisAccntOnway2.setOrderNo(orderNo);
        HisAccntOnway2 hisAccntOnway2Info = baseService.selectHisAccntOnway2(hisAccntOnway2);//在途2账户总额

        Long onway2Amt = 0L;
        if (ToolUtil.isNotEmpty(hisAccntOnway2Info)) {
            onway2Amt = hisAccntOnway2Info.getEventAmt();//记录的在途2金额
        }


        String accntType = withDrawAccnt.getAccntType();//账户类型
        Long beforeMchAmt = depositoryAccnt.getRemainAmt();//存管户余额（交易记录前）
        String transtionalNo = UUID.randomUUID().toString().replace("-", "").toLowerCase();//事务号
        Date transTime = new Date();
        if ("1".equals(withDrawInfo.getRemark1())) {//flag=1：非超额提现，不需要准备金; flag=2:非超额提现，需要准备金; flag =3:超额提现，但不需要准备金;flag=4:超额提现，需要准备金
            //更新存管户余额
            updateDepository(depositoryAccnt, amt);
        } else if ("2".equals(withDrawInfo.getRemark1())) {
            //记还准备金交易记录表（记一笔退款加回去准备金的记录，并记录）
            insetMchAccntChargeUp(transTime, mchNo, Math.abs(prepayAmt));//实际还准备金应该是7，但是子商户可用总余额变更后，原先的写法就不生效了
            //更新准备金账户（把扣减的准备金加回去）
            updatePrepay(prepayAccnt, Math.abs(prepayAmt));
            //记准备金交易记录表（记一笔退款加回去准备金的记录）
            insertHisPrepay(transTime, mchNo, orderNo, Math.abs(prepayAmt), beforePrepayAmt, PayConstant.DEPOSIT_TRAN_WITHDRAW_REFUND);
            //更新存管户余额（增加准备金过来的钱，减去提现的钱）//分支
            updateDepository(depositoryAccnt, amt - Math.abs(prepayAmt));
        } else if ("3".equals(withDrawInfo.getRemark1())) {
            //在途2记录一笔超额提现退回记录
//            insertMchAccntOnway(transTime, mchNo, orderNo, Math.abs(onway2Amt), onway2Accnt.getBalance(), Integer.parseInt(withDrawInfo.getRemark1()));
//            //更改在途2账户（把记录的在途2的明细退回去）
//            updateOnway2(mchNo, Math.abs(onway2Amt));
            //更新存管户月（减去提现的钱）
            updateDepository(depositoryAccnt, amt);
        } else if ("4".equals(withDrawInfo.getRemark1())) {
            //在途2记录超额提现记录
//            insertMchAccntOnway(transTime, mchNo, orderNo, Math.abs(onway2Amt), onway2Accnt.getBalance(), Integer.parseInt(withDrawInfo.getRemark1()));
//            //更新在途2账户余额
//            updateOnway2(mchNo, Math.abs(onway2Amt));
            //记还准备金交易记录表
            insetMchAccntChargeUp(transTime, mchNo, Math.abs(prepayAmt));
            //记录准备金交易记录明细表
            insertHisPrepay(transTime, mchNo, orderNo, Math.abs(prepayAmt), beforePrepayAmt, PayConstant.DEPOSIT_TRAN_WITHDRAW_REFUND);
            //减少准备金余额
            updatePrepay(prepayAccnt, Math.abs(prepayAmt));
            //更新存管户余额（把扣除的钱加回去，提现金额-扣除的准备金）
            updateDepository(depositoryAccnt, amt - Math.abs(prepayAmt));// 9 - 1   9-9
        }
//                int afterDepositortAmt = (int)(Double.valueOf(depositoryAccnt.getRemain_amt())-amt);
        //更新提现账户
        Long transAmt = 0L;
        if (onway2Amt != 0) {
            transAmt = Math.abs(onway2Amt);
        }
        withDrawAccnt.setRemainAmt(amt - transAmt);
        withDrawAccnt.setUpdateTime(new DateTime());
        baseService.updateMchAmtNoZero(withDrawAccnt);
        //更新商户可用总余额
        if (prepayAmt != 0) {
            transAmt = Math.abs(prepayAmt);
        }
        countAmtAccnt.setRemainAmt(amt - transAmt);
        countAmtAccnt.setUpdateTime(new DateTime());
        baseService.updateMchAmtNoZero(countAmtAccnt);
        //插入存管户历史交易明细数据
        insertHisMch(transTime, transtionalNo, mchNo, orderNo, Math.abs(depositoryAccnt.getRemainAmt()), beforeMchAmt, beforeMchAmt + Math.abs(depositoryAccnt.getRemainAmt()), "withdraw_refund");
        //插入提现账户历史交易明细数据
        insertWithdrawAccnt(transTime, transtionalNo, accntType, mchNo, mchAccntNo, orderNo, amt, beforeWithDrawAmt, beforeWithDrawAmt + amt, "withdraw_refund");

        updateWithDrawInfo(orderNo,mchNo,status,errMsg);


        //如果提现时包含手续费，则需要将提现手续费退还

        if(0L!=withDrawInfo.getTransFee()){
            if("1".equals(withDrawInfo.getRemark1()) || "3".equals(withDrawInfo.getRemark1())){
                updateDepository(depositoryAccnt, withDrawInfo.getTransFee());
            }else if("2".equals(withDrawInfo.getRemark1()) || "4".equals(withDrawInfo.getRemark1())){

                insetMchAccntChargeUp(transTime, mchNo, Math.abs(prepayAmt2));

                //更新准备金账户（把扣减的准备金加回去）
                updatePrepay(prepayAccnt, Math.abs(prepayAmt2));

                //记准备金交易记录表（记一笔退款加回去准备金的记录）
                insertHisPrepay(transTime, mchNo, orderNo, Math.abs(prepayAmt2), Math.abs(prepayAmt)+beforePrepayAmt, "refund_poundage");

                //更新存管户余额（增加准备金过来的钱，减去提现的钱）//分支
                updateDepository(depositoryAccnt, withDrawInfo.getTransFee() - Math.abs(prepayAmt2));

            }

            /*//如果需要扣除手续费，则将手续费增加到分润账户中
            if(flag == 2 || flag ==4){
                insetMchAccntChargeUp(transTime, mchNo, -(long) fixedPoundage);
                updatePrepay(prepayAccnt, -(long) fixedPoundage);
                insertHisPrepay(transTime, mchNo, orderNo, -(long) fixedPoundage, beforePrepayAmt -Math.abs(amt - accntCount), "poundage");
                updateDepository(depositoryAccnt, -accntCount);
            }else if(flag == 1 || flag ==3){
                updateDepository(depositoryAccnt, -(long) fixedPoundage);
            }
            //插入存管户历史交易明细数据
            insertHisMch(transTime, transtionalNo, mchNo, orderNo, -Math.abs(depositoryAccnt.getRemainAmt()), beforeMchAmt - Math.abs(depositoryAccnt.getRemainAmt()), beforeMchAmt - Math.abs(depositoryAccnt.getRemainAmt()) -Math.abs(depositoryAccnt.getRemainAmt()) , "poundage");
            */
            long fixedPoundage = withDrawInfo.getTransFee();
            //如果需要扣除手续费，则将手续费增加到分润账户中
            insertHisMch(transTime, transtionalNo, mchNo, orderNo, fixedPoundage, beforeMchAmt + Math.abs(depositoryAccnt.getRemainAmt()), beforeMchAmt + Math.abs(depositoryAccnt.getRemainAmt())+fixedPoundage , "refund_poundage");

            //更改分润账户余额
            updateMchAccnt(mchNo, -fixedPoundage);
            MchAccnt profitAccnt = queryMchAccntByMchNo(mchNo,PayConstant.DEPOSIT_PROFIT);
            //记录分润账户明细
            insertHisMchProfit(transtionalNo, orderNo,"refund_poundage" ,mchNo, profitAccnt.getRemainAmt(),  -fixedPoundage, profitAccnt.getRemainAmt()-fixedPoundage,transTime);
            //更新提现账户
            withDrawAccnt.setRemainAmt(fixedPoundage);
            withDrawAccnt.setUpdateTime(new DateTime());
            baseService.updateMchAmtNoZero(withDrawAccnt);
            //插入提现账户历史交易明细数据
            insertWithdrawAccnt(transTime, transtionalNo, accntType, mchNo, mchAccntNo, orderNo, fixedPoundage, beforeWithDrawAmt + amt, beforeWithDrawAmt + amt + fixedPoundage, "refund_poundage");
        }
        //插入提现记录表
//        insertWithdrawInfo(transtionalNo,outoderNo,cardNo, mchNo,mchAccntNo,orderNo, amt,beforeWithDrawAmt+amt,Integer.parseInt(withDrawInfo.getRemark1()));

    }


    /**
     * 定时更新 两个工作日前的 普通网银的提现状态 为成功
     *
     * param dateNew
     * throws ParseException
     * throws InterruptedException
     */
    @Override
    public void updateWithDrawInfoByTime(String dateNew) throws  InterruptedException {
        //查出日期之前的所有提现记录，全部置为成功
        WithDrawInfo withDrawInfo = new WithDrawInfo();
        withDrawInfo.setStatus("3");
        withDrawInfo.setTransDate(dateNew);
        //插入
        List<WithDrawInfo> withDrawInfoList = baseService.selectWithDrawInfoByDate(withDrawInfo);
        for (WithDrawInfo withDrawInfo1 : withDrawInfoList) {
            //更改提现记录状态、发送异步通知接口，五分钟一次，共发送5次
            updateWithDrawInfo(withDrawInfo1.getOrderNo(), withDrawInfo1.getMchNo(), "1", "提现成功");
            asyncTask.withDrawNotify(withDrawInfo1, withDrawInfo1.getNotifyUrl(), "1", "提现成功！");
        }
    }


    /**
     * 插入分润账户资金明细数据
     * <p>
     * param accnt
     * param mchNo
     * param amt
     * param afertAmt
     * return
     */
    public int insertHisMchProfit(String transcationNo, String orderNo,String event,String mchNo, Long amt, Long amount, Long afertAmt,Date date) {
        //插入分润商户账户资金明细表
        HisAccntProfile hisAccntProfile = new HisAccntProfile( );
        hisAccntProfile.setMchNo(mchNo);
        hisAccntProfile.setOrderNo(orderNo);//订单号
        hisAccntProfile.setTransactionNo(transcationNo);//事务号
        hisAccntProfile.setEvent(event);//事件名称
        hisAccntProfile.setEventAmt(amount);//事件金额
        hisAccntProfile.setEventTime(date);//事件时间
        hisAccntProfile.setAccntAmtBefore(amt);//事件发生前余额
        hisAccntProfile.setAccntAmtAfter(afertAmt);//事件发生后金额
        hisAccntProfile.setCreateTime(date);//创建时间
        return baseService.insertHisProfile(hisAccntProfile);
    }


    /**
     * 根据电商平台号，账户号查询子商户账户信息
     * <p>
     * param mchNo
     * param mchAccntNo
     * return
     */
    private MchAccnt queryMchAccntByMchNo(String mchNo, String accntType) {
        MchAccnt mchAccnt = new MchAccnt( );
        MchAccnt mchAccntBefore = null;
        mchAccnt.setAccntType(accntType);//账户号
        mchAccnt.setMchNo(mchNo);
        List<MchAccnt> mchAccntList = mchAccntMapper.selectMchAccnt(mchAccnt);//根据账户号商户号，查询账户信息
        if (ToolUtil.isNotEmpty(mchAccntList)) {
            mchAccntBefore = mchAccntList.get(0);
        }
        return mchAccntBefore;
    }




    public String testTransactional(){
        insetMchAccntChargeUp(new Date(), "100090902", 3L);
        String isSuper = "1";
        try{
            WithdrawPay withdrawPay ;
            //如果是超级网银
            if ("1".equals(isSuper)) {
                withdrawPay = WithdrawPayUtil.withdrawPay("80000001", "123222009130", "N", "N", "6226097807427613", "范晶晶", "招商银行", "308584000013", "深圳", AmountUtil.convertCent2Dollar(String.valueOf("1")), isSuper, "0", "超级网银--提现");
            }
        }catch (Exception e){
            System.out.println("-----");
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        //http代码

        return  null;
    }
}
